﻿/// <reference path="../Controls/BaseComplexValueControl.js" />
/// <reference path="RepeaterValue.js" />
/// <reference path="RepeaterItem.js" />
/// <reference path="RepeaterPager.js" />
/// <reference path="../General/Extensions/Array.js" />
/// <reference path="../Extensions/Number.js" />





var $Repeater = TA.Turbo.Controls.Repeater = function Repeater(clientId)
{
	if (Function.IsInherit(arguments)) return;

	this.BaseComplexValueControl(clientId);

	this._viewItemTemplate = new $MarkupTemplate();
	this._editItemTemplate = new $MarkupTemplate();
}
$Repeater.Inherit(TA.Turbo.Controls.BaseComplexValueControl);

var ____a;
if (____a)
{
	$Repeater = TA.Turbo.Controls.BaseComplexValueControl;
	$Repeater.prototype.BaseComplexValueControl = new TA.Turbo.Controls.BaseComplexValueControl();

	$Repeater.prototype._pagerTop = new $RepeaterPager();
	$Repeater.prototype._pagerBottom = new $RepeaterPager();
	$Repeater.prototype._oldPagesRange = new Range();
	$Repeater.prototype._containerElement = document.getElementById("s");

	$Repeater.prototype._items = new Array();
	$Repeater.prototype._unusedItems = new Array();
	$Repeater.prototype._allItems = new Array();
	$Repeater.prototype._viewItemTemplate = new $MarkupTemplate();
	$Repeater.prototype._editItemTemplate = new $MarkupTemplate();

	$Repeater.prototype.get_Pager = function get_Pager() { return new $PagerSettings(); };
	$Repeater.prototype.set_Pager = function set_Pager(value) { }

	$Repeater.prototype.get_PageIndex = function get_PageIndex() { return 0 };
	$Repeater.prototype.set_PageIndex = function set_PageIndex(value) { }

	$Repeater.prototype.get_SortDirection = function get_SortDirection() { return 0; };
	$Repeater.prototype.set_SortDirection = function set_SortDirection(value) { }

	$Repeater.prototype.get_SortExpression = function get_SortExpression() { return ""; };
	$Repeater.prototype.set_SortExpression = function set_SortExpression(value) { }

	$Repeater.prototype.get_SortingMode = function get_SortingMode() { return 0; };
	$Repeater.prototype.set_SortingMode = function set_SortingMode(value) { }

	$Repeater.prototype.get_DisplayNewItem = function get_DisplayNewItem() { return true; };
	$Repeater.prototype.set_DisplayNewItem = function set_DisplayNewItem(value) { }

	$Repeater.prototype.get_DisplayEdit = function get_DisplayEdit() { return true; };
	$Repeater.prototype.set_DisplayEdit = function set_DisplayEdit(value) { }
}

$Repeater.NotLoaded = "NOTLOADED";

$Repeater.prototype._firstValueSet = true;

$PropertyDefinition.Define($Repeater, "Pager", "P",
	new $PagerSettings(),
	{
		Serializable: $PagerSettings
	});
$PropertyDefinition.Define($Repeater, "PageIndex", "PI", 0);
$PropertyDefinition.Define($Repeater, "SortDirection", "SD", $SortDirection.Ascending);
$PropertyDefinition.Define($Repeater, "DefaultSortDirection", "DD", $SortDirection.Ascending);
$PropertyDefinition.Define($Repeater, "SortExpression", "SE", "");
$PropertyDefinition.Define($Repeater, "SortingMode", "SM", $SortingMode.Automatic);
$PropertyDefinition.Define($Repeater, "DisplayNewItem", "DN", false);
$PropertyDefinition.Define($Repeater, "DisplayEdit", "DE", false);

$Repeater.DefineEvent(new $ClientEvent("BindItem"));
$Repeater.DefineEvent(new $ClientEvent("ParseRenderedItems"));
$Repeater.DefineEvent(new $ClientEvent("GetArgumentByEntry"));
$Repeater.DefineEvent(new $ServerEvent("ItemAdded"));
$Repeater.DefineEvent(new $ServerEvent("ItemUpdated"));
$Repeater.DefineEvent(new $ServerEvent("ItemDeleted"));
$Repeater.DefineEvent(new $ServerEvent("LoadEntries"));
$Repeater.DefineEvent(new $ServerEvent("Command"));


//static
$Repeater.get_Item = function get_Item()
{
	return this._item;
}


//instance

// PUBLIC

// PROPERTIES
$Repeater.prototype.get_Entries = function get_Entries()
{
	/// <summary>Test</summary>
	/// <returns type="array">array</returns>
	return this._objectValue.Entries;
	return new Array();
}
$Repeater.prototype.get_ContainerElement = function get_ContainerElement()
{
	return this._containerElement;
	return document.getElementById("asd");
}
$Repeater.prototype.get_Items = function get_Items()
{
	return this._items;
}
$Repeater.prototype.get_UnusedItems = function get_UnusedItems()
{
	return this._unusedItems;
}
$Repeater.prototype.get_AllItems = function get_AllItems()
{
	return this._allItems;
}
$Repeater.prototype.get_DefaultItemType = function get_DefaultItemType()
{
	return this.get_DisplayEdit() ? $RepeaterItemType.Edit : $RepeaterItemType.View;
}
$Repeater.prototype.get_NumPages = function get_NumPages()
{
	return Math.ceil(this.get_Entries().length / this.get_Pager().Size);
}
$Repeater.prototype.get_ActualPageIndex = function get_ActualPageIndex()
{
	return Math.max(0, Math.min(this.get_NumPages() - 1, this.get_PageIndex()));
}
$Repeater.prototype.get_PagesRange = function get_PagesRange()
{
	return new Range(
		Math.max(0, Math.min(this.get_ActualPageIndex() - Math.floor(this.get_Pager().ButtonCount / 2), this.get_NumPages() - this.get_Pager().ButtonCount)),
		Math.min(this.get_NumPages(), Math.max(this.get_ActualPageIndex() + Math.floor(this.get_Pager().ButtonCount / 2) + 1, this.get_Pager().ButtonCount)));
}
$Repeater.prototype.get_IsValid = function get_IsValid()
{
	var isValid = true;
	for (var iItem = 0; iItem < this._items.length; ++iItem)
	{
		var item = this._items[iItem];
		if (item.get_Visible())
			isValid = isValid && item.get_IsValid();
	}
	return isValid;
}
$Repeater.prototype.get_ViewItemTemplate = function get_ViewItemTemplate()
{
	return this._viewItemTemplate;
}
$Repeater.prototype.get_EditItemTemplate = function get_EditItemTemplate()
{
	return this._editItemTemplate;
}












// METHODS
$Repeater.prototype.Init = function Init()
{
	this.BaseComplexValueControl.Init.call(this);

	this._objectValue = new $RepeaterValue();

	this._items = new Array();
	this._unusedItems = new Array();
	this._allItems = new Array();

	this._Init_ContainerElement();
	this._Init_Pagers();
}
$Repeater.prototype._Init_ContainerElement = function _Init_ContainerElement()
{
	var myself = this;
	this.get_Control().PerformRecursive(function(elem)
	{
		if (elem.getAttribute("ItemsContainer") == "1")
		{
			myself._containerElement = elem;
			return true;
		}
	});

	if (this._containerElement == null)
	{
		Throw("Repeater " + this._controlId + " couldn't determine its item container element.");
	}
}
$Repeater.prototype._Init_Pagers = function _Init_Pagers()
{
	this._pagerTop = new $RepeaterPager(this.get_Control().FindFirstChild(".pager.top"), this);
	this._Init_Pagers_One(this._pagerTop);

	this._pagerBottom = new $RepeaterPager(this.get_Control().FindFirstChild(".pager.bottom"), this);
	this._Init_Pagers_One(this._pagerBottom);
}
$Repeater.prototype._Init_Pagers_One = function _InitPager(pager)
{
	pager.AddEvent("PageIndexChanged", this._pager_PageIndexChanged, this);
	pager.Init();
}
$Repeater.prototype.Load = function Load()
{
	this.BaseComplexValueControl.Load.call(this);

	this.get_ViewItemTemplate()._ProcessMarkupAndScript(this.get_Control());
	this.get_EditItemTemplate()._ProcessMarkupAndScript(this.get_Control());

	this._Load_ParseRenderedItems();

	this._OnValueSet();
}
$Repeater.prototype._Load_ParseRenderedItems = function _Load_ParseRenderedItems()
{
	this._items.AddRange(this._GetRenderedItems(this._containerElement));
}
$Repeater._IsIgnoredTagName = function _IsIgnoredTagName(elem)
{
	return elem.tagName == null;// || elem.tagName == "SCRIPT" || elem.tagName == "LINK");
}
$Repeater.prototype._GetRenderedItems = function _GetRenderedItems(containerElement)
{
	var elements = new Array();

	// first try to parse automatically, using tagName matching
	var parsed = true;
	var pattern = new Array();
	var iPattern = 0;

	var cn = containerElement.get_ChildNodes(), cnl = cn.length;
	for (var iChildNode = 0; iChildNode < cnl; ++iChildNode)
	{
		var childNode = cn[iChildNode];
		if ($Repeater._IsIgnoredTagName(childNode))
			continue;

		if (elements.length <= 1)
		{
			if (elements.length == 0)
			{
				elements.push(new Array());
			}

			if (pattern.length == 0)
			{
				elements[0].push(childNode);
				pattern.push(childNode.tagName);
			}
			else
			{
				var good = true;
				var iSkip = 0;
				for (var iTest = 0; iTest < pattern.length; ++iTest)
				{
					if (iChildNode + iTest + iSkip >= cnl)
					{
						good = false;
						break;
					}

					if ($Repeater._IsIgnoredTagName(cn[iChildNode + iTest + iSkip]))
					{
						++iSkip;
						--iTest;
						continue;
					}

					if (cn[iChildNode + iTest + iSkip].tagName != pattern[iTest])
					{
						good = false;
						break;
					}
				}

				if (!good)
				{
					elements[0].push(childNode);
					pattern.push(childNode.tagName);
				}
				else
				{
					elements.push(new Array());
					elements[elements.length - 1].push(childNode);
					iPattern = 1;
					if (iPattern == pattern.length)
					{
						iPattern = 0;
						elements.push(new Array());
					}
				}
			}
		}
		else
		{
			if (childNode.tagName == pattern[iPattern])
			{
				elements[elements.length - 1].push(childNode);
				++iPattern;
				if (iPattern == pattern.length)
				{
					iPattern = 0;
					elements.push(new Array());
				}
			}
			else
			{
				for (var iElemGroup = 1; iElemGroup < elements.length; ++iElemGroup)
				{
					var elemGroup = elements[iElemGroup];
					for (var iElement = 0; iElement < elemGroup.length; ++iElement)
					{
						var elem = elemGroup[iElement];
						elements[0].push(elem);
						pattern.push(elem.tagName);
					}
				}
				elements.splice(1, elements.length - 1);
				pattern.push(childNode.tagName);
				elements[0].push(childNode);
			}
		}
	}

	if (!parsed)
	{ // if not, try the event
		if (this.IsHandled("ParseRenderedItems"))
		{
			var args = {
				ContainerElement: containerElement,
				Items: new Array()
			};
			this.RaiseEvent("ParseRenderedItems", args);

			elements = args.Items;
			parsed = true;
		}
	}

	var res = new Array();

	if (parsed)
	{
		for (var iItem = 0; iItem < elements.length; ++iItem)
		{
			var itemElements = elements[iItem];

			var item = new $RepeaterItem(this, $RepeaterItemType.View, (this._items.length + res.length).toString(), itemElements);
			item.set_ValueIndex(iItem + this.get_PageIndex() * this.get_Pager().Size);
			res.push(item);
		}
	}

	return res;
}
$Repeater.prototype.AddEntry = function AddEntry(entry)
{
	this.get_Entries().push(entry);
	this._OnValueChanged();
}
$Repeater.prototype.RemoveEntry = function RemoveEntry(entry)
{
	this.get_Entries().Remove(entry);
	this._OnValueChanged();
}

// EVENTS
$Repeater.prototype._OnPagerChanged = function _OnPagerChanged()
{
	this.RaiseEvent("PagerChanged");

	this.UpdatePages();
}
$Repeater.prototype._OnPageIndexChanged = function _OnPageIndexChanged()
{
	this.RaiseEvent("PageIndexChanged");

	this._HideEdits();
	this.UpdateDisplay();
	this.UpdatePages(true);
}
$Repeater.prototype._OnSortExpressionChanged = function _OnSortExpressionChanged()
{
	this.RaiseEvent("SortExpressionChanged");

	this._HideEdits();
	this._SortParameterChanged();
}
$Repeater.prototype._OnSortDirectionChanged = function _OnSortDirectionChanged()
{
	this.RaiseEvent("SortDirectionChanged");

	this._HideEdits();
	this._SortParameterChanged();
}



// INTERNAL
$Repeater.prototype._GetTemplateByType = function _GetTemplateByType(type)
{
	switch (type)
	{
		case $RepeaterItemType.View:
			return this._viewItemTemplate;
		case $RepeaterItemType.Edit:
			return this._editItemTemplate;
	}
}
$Repeater.prototype._HideEdits = function _HideEdits()
{
	for (var iItem = 0; iItem < this._items.length; ++iItem)
	{
		if (this._items[iItem].get_Type() == $RepeaterItemType.Edit)
			this._items[iItem].Hide();
	}
}
$Repeater.prototype.set_Value = function set_Value(value)
{
	Throw("Value can't be set on the Repeater.");
}
$Repeater.prototype.set_SerializedValue = function set_SerializedValue(json)
{
	this.get_Value().Deserialize(json);
	this._OnValueChanged();
	this._OnValueSet();
}
$Repeater.prototype._OnValueSet = function _OnValueSet()
{
	if (this.get_Value() == null)
		this._objectValue = new $RepeaterValue();

	if (this.get_Value().Entries == null)
		this.get_Value().Entries = new Array();


	for (var i = 0; i < this.get_Value().FirstIndex; ++i)
		this.get_Entries().splice(0, 0, $Repeater.NotLoaded);
	while (this.get_Entries().length < this.get_Value().NumEntries)
	{
		this.get_Entries().push($Repeater.NotLoaded);
	}

	for (var i = 0; i < this._items.length; ++i)
	{
		if (this._items[i].get_Type() == $RepeaterItemType.Edit)
			this._items[i].Hide();
	}

	if (this.get_DisplayNewItem())
		this.FireCommand("New");
	else
	{
		this.UpdatePages(false); // we update the pages in any case

		if (this._firstValueSet) // this is the first time
		{
			// the items might or might not be rendered at this point
			// but we can only check if the items were rendered and parsed
			// meaning if they were rendered but not parsed, we wouldn't know that
			if (this._items.length != 0) //  were items rendered and parsed?
			{// we don't need to re-bind them
			}
			else
			{
				// they might've been rendered but because we couldn't parse them, we need to clear the container element
				this.get_ContainerElement().ClearChildNodes();

				this.UpdateDisplay(); // display items
			}
		}
		else
		{
			if (this._items.length == 0)//  there are no items
			{
				// they might've been rendered but because we couldn't parse them, we need to clear the container element
				this.get_ContainerElement().ClearChildNodes();
			}
			this.UpdateDisplay(); // display items
		}
	}
	this._firstValueSet = false;
}
$Repeater.prototype._pager_PageIndexChanged = function _pager_PageIndexChanged(e)
{
	this.set_PageIndex(e.PageIndex);
}
$Repeater.prototype._SortParameterChanged = function _SortParameterChanged()
{
	if (this._sortTimeoutId == null)
	{
		this._sortTimeoutId = setTimeout(this._SortParameterChanged_Perform.bind(this), 10);
	}
}
$Repeater.prototype._SortParameterChanged_Perform = function _SortParameterChanged_Perform()
{
	this._sortTimeoutId = null;

	var needToCallServer = true;
	if (this.get_SortingMode() == $SortingMode.Automatic)
	{
		needToCallServer = !this._AllEntriesLoaded(0, this.get_Entries().length);
	}
	if (needToCallServer)
	{
		for (var iEntry = 0; iEntry < this.get_Entries().length; ++iEntry)
			this.get_Entries()[iEntry] = $Repeater.NotLoaded;
		this.UpdateDisplay();
	}
	else
	{
		var 
			good = false,
			t,
			c = 1.3,
			entries = this.get_Entries(),
			j,
			k = Math.max(Math.round(entries.length / c), entries.length - 1),
			sortExpression = this.get_SortExpression(),
			sortDirection = this.get_SortDirection();

		if (sortDirection == $SortDirection.Ascending)
		{
			while (!good)
			{
				good = true;
				for (var iEntry = 0; iEntry < entries.length - k; ++iEntry)
				{
					j = iEntry + k;
					if (entries[iEntry][sortExpression] > entries[j][sortExpression])
					{
						t = entries[iEntry];
						entries[iEntry] = entries[j];
						entries[j] = t;

						good = false;
					}
				}
				if (k > 1)
					good = false;
				k = Math.min(Math.round(k / c), 1);
			}
		}
		else
		{
			while (!good)
			{
				good = true;
				for (var iEntry = 0; iEntry < entries.length - k; ++iEntry)
				{
					j = iEntry + k;
					if (entries[iEntry][sortExpression] < entries[j][sortExpression])
					{
						t = entries[iEntry];
						entries[iEntry] = entries[j];
						entries[j] = t;

						good = false;
					}
				}
				if (k > 1)
					good = false;
				k = Math.min(Math.round(k / c), 1);
			}
		}


		this.UpdateDisplay();
	}
}
